package com.tianji.learning.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.db.DbRuntimeException;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.HandeLearningRecordCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author wxh
 * @since 2024-08-22
 */
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    @Autowired
    private ILearningLessonService iLearningLessonService;

    @Autowired
    private HandeLearningRecordCache handeLearningRecordCache;

    @Autowired
    private CourseClient courseClient;

    /**
     * 查询当前用户指定课程的学习进度(Day 3  第一个接口)
     *
     * @param courseId 课程id
     * @return 课表信息、学习记录及进度信息
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //查询课表信息
        LearningLesson learningLesson = iLearningLessonService.queryCourseInfoByCourseId(courseId, UserContext.getUser());
        if (ObjectUtil.isEmpty(learningLesson)) {
            return null;
        }
        //根据课表id查询课程记录信息
        List<LearningRecord> records = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, learningLesson.getId())
                .list();
        //课表id                       最近学习的小节Id
        return LearningLessonDTO.of(learningLesson.getId(), learningLesson.getLatestSectionId(),
                BeanUtils.copyList(records, LearningRecordDTO.class));//提供一个集合，将另一个新的类放入集合，重新构建新的集合
    }

    /**
     * 新增学习记录
     *
     * @param formDTO
     */
    @Override
    public void addLearningRecord(LearningRecordFormDTO formDTO) {
        //先判断是否是考试
        boolean firstFinish = formDTO.getSectionType() == SectionType.VIDEO ? addVideoRecord(formDTO) : addExamRecord(formDTO);
        if (!firstFinish && formDTO.getDuration() == -1) {
            // 如果firstFinished为false，并且duration为-1证明本次是暂存进度至redis，无需处理课表数据，而是等待延时检测任务处理
            return;
        }
        //处理课表数据
        LearningLessonData(firstFinish, formDTO);


    }

    /**
     * 处理课表相关数据
     *
     * @param firstFinish
     * @param formDTO
     */
    private void LearningLessonData(boolean firstFinish, LearningRecordFormDTO formDTO) {
        //先查询我的课表
        LearningLesson lessonInfo = iLearningLessonService.getById(formDTO.getLessonId());
        if (ObjectUtil.isEmpty(lessonInfo)) {
            throw new DbRuntimeException("查询我的课表数据为空");
        }

        boolean allVedioFinish = false;
        if (firstFinish) {
            //根据课程id查询课程信息
            CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lessonInfo.getCourseId(), false, false);
            //视频数据处理
            allVedioFinish = lessonInfo.getLearnedSections() + 1 >= courseInfo.getSectionNum();
        }
        boolean update = iLearningLessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId, formDTO.getSectionId())
                .set(LearningLesson::getLatestLearnTime, formDTO.getCommitTime())
                .set(firstFinish, LearningLesson::getLearnedSections, lessonInfo.getLearnedSections() + 1)
                .set(lessonInfo.getStatus() == LessonStatus.NOT_BEGIN, LearningLesson::getStatus, LessonStatus.LEARNING)
                .set(allVedioFinish, LearningLesson::getStatus, LessonStatus.FINISHED)
                .eq(LearningLesson::getId, formDTO.getLessonId())
                .update();

        if (!update) {
            throw new DbException("修改课表数据失败！");
        }


    }

    /**
     * 新增学习记录
     *
     * @return
     */
    private boolean addVideoRecord(LearningRecordFormDTO formDTO) {
        //根据lenssId与小节id查询学习记录表是否有该数据
        LearningRecord oldrecord = queryLearningRecord(formDTO.getLessonId(), formDTO.getSectionId());
        if (ObjectUtil.isEmpty(oldrecord)) {
            //无新增学习记录
            //对象拷贝
            LearningRecord learningRecord = BeanUtils.copyBean(formDTO, LearningRecord.class);
            //更新学习记录
            learningRecord.setUserId(UserContext.getUser());
            //写入数据库
            boolean save = save(learningRecord);
            if (ObjectUtil.isEmpty(save)) {
                throw new DbRuntimeException("新增学习记录失败");
            }
            return false;
        }
        //判断是否是第一次学完
        boolean finish = !oldrecord.getFinished() && oldrecord.getMoment() << 1 >= formDTO.getDuration();
        if (!finish) {
            LearningRecord learningRecord = new LearningRecord();
            learningRecord.setId(oldrecord.getId());
            learningRecord.setLessonId(formDTO.getLessonId());
            learningRecord.setSectionId(formDTO.getSectionId());
            learningRecord.setMoment(formDTO.getMoment());
            learningRecord.setFinished(oldrecord.getFinished());
            //没有学完，就覆盖redis中的学习进度，提交延时任务
            handeLearningRecordCache.updateRedisDateAndDelayCommit(learningRecord);
            formDTO.setDuration(-1);
            return false;
        }
        // 4.2、更新学习记录（一定要更新的字段：moment，第一次学完时更新两个字段：finished、finish_time）
        boolean update = this.lambdaUpdate()
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getFinishTime, formDTO.getCommitTime())
                .set(LearningRecord::getMoment, formDTO.getMoment())
                .eq(LearningRecord::getId, oldrecord.getId())
                .update();
        if (!update) {
            throw new DbRuntimeException("更新学习记录失败");
        }
        //删除redis中的学习记录
        handeLearningRecordCache.removeRedisLearningRecord(formDTO.getLessonId(), formDTO.getSectionId());


        return true;
    }


    /**
     * 新增考试记录
     *
     * @return
     */
    private boolean addExamRecord(LearningRecordFormDTO formDTO) {
        //对象拷贝
        LearningRecord examRecord = BeanUtils.copyBean(formDTO, LearningRecord.class);
        //填充缺失数据
        examRecord.setUserId(UserContext.getUser());
        examRecord.setFinished(true);
        examRecord.setFinishTime(formDTO.getCommitTime());
        //写入数据库
        boolean save = save(examRecord);
        if (ObjectUtil.isEmpty(save)) {
            throw new DbRuntimeException("新增考试记录失败");
        }
        //返回标识
        return true;
    }

    /**
     * 查询学习记录是否存在
     *
     * @param lessonId
     * @param sectionId
     * @return
     */
    private LearningRecord queryLearningRecord(Long lessonId, Long sectionId) {
        //先从redis中查询
        LearningRecord oldrecord = handeLearningRecordCache.queryRedisData(lessonId, sectionId);
        if (ObjectUtil.isNotEmpty(oldrecord)) {
            //存在则直接返回
            return oldrecord;
        }
        //redis没有再从数据库查
        oldrecord = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if (ObjectUtil.isEmpty(oldrecord)) {
            return null;
        }
        //将数据查出的数据放入redies
        handeLearningRecordCache.writeRedisLearningRecord(oldrecord);
        //返回学习记录
        return oldrecord;
    }

}
